package com.ll.domain.ranking.biz.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ll.app.api.req.AddRankingReqDTO;
import com.ll.app.api.req.ListRankingReqDTO;
import com.ll.app.api.req.PageRankingReqDTO;
import com.ll.app.api.req.RankingAuthenticationReqDTO;
import com.ll.base.constant.LlConstants;
import com.ll.base.dto.PageResultDTO;
import com.ll.base.enums.ResultCodeEnum;
import com.ll.base.exception.CustomRunTimeException;
import com.ll.base.util.ListUtil;
import com.ll.base.util.ScalarUtil;
import com.ll.dal.po.RankingPO;
import com.ll.dal.po.UserPO;
import com.ll.domain.dingtalk.base.DingTalkMessageBaseService;
import com.ll.domain.pk.convert.PkConvert;
import com.ll.domain.pk.event.producer.AddPkEvent;
import com.ll.domain.ranking.base.RankingBaseService;
import com.ll.domain.ranking.biz.RankingDomainService;
import com.ll.domain.ranking.convert.RankingConvert;
import com.ll.domain.ranking.dto.RankingDTO;
import com.ll.domain.ranking.enums.RankingStatusEnum;
import com.ll.domain.ranking.enums.RankingTypeEnum;
import com.ll.domain.ranking.producer.CleanRankingEvent;
import com.ll.domain.user.base.UserBaseService;
import com.ll.domain.user.dto.UserDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class RankingDomainServiceImpl implements RankingDomainService {

    private final RankingBaseService rankingBaseService;
    private final UserBaseService userBaseService;
    private final DingTalkMessageBaseService dingTalkMessageBaseService;
    private final ApplicationEventPublisher applicationEventPublisher;
    /**
     * 排名前5的需要通知到大群
     */
    private final Integer NOTIFY_RANKING = 5;
    private final Integer RANKING_INTEGRAL = 50;

    @Override
    public PageResultDTO<RankingDTO> page(PageRankingReqDTO pageReq) {
        PageResultDTO<RankingDTO> page = rankingBaseService.page(pageReq);
        this.buildBizData(page.getDatas());
        return page;
    }

    @Override
    public List<RankingDTO> list(ListRankingReqDTO reqDTO) {
        List<RankingPO> list = rankingBaseService.list(new LambdaQueryWrapper<RankingPO>()
                .eq(reqDTO.getType() != null, RankingPO::getType, reqDTO.getType())
                .eq(reqDTO.getStatus() != null, RankingPO::getStatus, reqDTO.getStatus())
                .eq(ScalarUtil.isNotEmpty(reqDTO.getStudentUid()), RankingPO::getStudentUid, reqDTO.getStudentUid())
                .orderByDesc(RankingPO::getSort).orderByDesc(RankingPO::getUtime)
        );
        List<RankingDTO> result = ListUtil.toList(list, RankingConvert::PO2DTO);
        this.buildBizData(result);
        return result;
    }

    @Override
    public void add(AddRankingReqDTO reqDTO) {
        if (ScalarUtil.isEmpty(reqDTO.getTenantId())) {
            reqDTO.setTenantId(LlConstants.DEFAULT_TENANT_ID);
        }

        RankingPO rankingOne = rankingBaseService.getRankingOne(reqDTO.getTenantId(), reqDTO.getStudentUid(), reqDTO.getType(), RankingStatusEnum.未认证);
        if (rankingOne != null) {
            throw new CustomRunTimeException(ResultCodeEnum.SOURCE_PK_EXIST_ERROR);
        }

        RankingPO rankingPO = RankingConvert.addRankingReqDTO2PO(reqDTO);
        UserDTO userDTO = userBaseService.getById(reqDTO.getTenantId(), reqDTO.getStudentUid(), true);
        if (userDTO.getIntegral() == null || userDTO.getIntegral() < RANKING_INTEGRAL) {
            throw new CustomRunTimeException(ResultCodeEnum.INTEGRAL_ERROR);
        }
        userBaseService.updateIntegral(userDTO, -RANKING_INTEGRAL);
        rankingBaseService.save(rankingPO);
    }

    @Override
    public void delete(Long id) {
        rankingBaseService.removeById(id);
    }

    @Override
    public void authentication(RankingAuthenticationReqDTO dto) {
        RankingPO po = rankingBaseService.getById(dto.getId());
        CustomRunTimeException.checkNull(po, " 打榜记录");

        if (dto.getTeacherUid().equals(po.getStudentUid())) {
            throw new CustomRunTimeException(ResultCodeEnum.APPLY_ERROR);
        }

        //删除老得认证记录
        RankingPO rankingOne = rankingBaseService.getRankingOne(po.getTenantId(), po.getStudentUid(), po.getType(), RankingStatusEnum.已认证);
        if (rankingOne != null) {
            //分数低于老得 就删除本次认证的数据
            if(rankingOne.getSort() <= dto.getSort()){
                rankingBaseService.removeById(rankingOne.getId());
            }else{
                rankingBaseService.removeById(dto.getId());
                return;
            }
        }

        rankingBaseService.authRanking(po.getId(), dto.getTeacherUid(), dto.getSort());
        if (ScalarUtil.isEmpty(dto.getTenantId())) {
            dto.setTenantId(LlConstants.DEFAULT_TENANT_ID);
        }
        Long ranking = rankingBaseService.getRanking(dto.getTenantId(), po.getStudentUid(), po.getType());
        if (ranking != null && ranking <= this.NOTIFY_RANKING) {
            RankingDTO rankingDTO = RankingConvert.PO2DTO(po);
            this.buildBizData(rankingDTO);
            dingTalkMessageBaseService.sendRankingNotify(rankingDTO, ranking, dto.getSort());
        }

    }

    @Override
    public void cleanRanking() {

        Map<RankingTypeEnum ,List<RankingDTO>> eventBody = new HashMap<>();
        for (RankingTypeEnum type : RankingTypeEnum.values()) {
            PageRankingReqDTO reqDTO = PageRankingReqDTO.builder()
                    .type(type)
                    .build();
            reqDTO.initPage();
            PageResultDTO<RankingDTO> page = rankingBaseService.page(reqDTO);
            this.buildBizData(page.getDatas());
            eventBody.put(type, page.getDatas());
        }

        //修改已经认证的数据
        rankingBaseService.cleanRanking();

        //添加事件发起
        applicationEventPublisher.publishEvent(new CleanRankingEvent(eventBody));
    }


    public void buildBizData(RankingDTO dto) {
        this.buildBizData(Arrays.asList(dto));
    }

    public void buildBizData(List<RankingDTO> list) {
        if (ScalarUtil.isEmpty(list)) {
            return;
        }

        List<Long> uid = ListUtil.toList(list, RankingDTO::getStudentUid);
        uid.addAll(ListUtil.toList(list, RankingDTO::getTeacherUid));
        List<UserDTO> byIds = userBaseService.getByIds(uid);
        Map<Long, UserDTO> longUserDTOMap = ListUtil.toMap(byIds, UserDTO::getId);
        list.forEach(r -> {
            if (ScalarUtil.isNotEmpty(r.getStudentUid()) && longUserDTOMap.containsKey(r.getStudentUid())) {
                UserDTO userDTO = longUserDTOMap.get(r.getStudentUid());
                r.setStudentName(userDTO.getUserName());
                r.setStudentLogo(userDTO.getLogo());
            }

            if (ScalarUtil.isNotEmpty(r.getTeacherUid()) && longUserDTOMap.containsKey(r.getTeacherUid())) {
                UserDTO userDTO = longUserDTOMap.get(r.getTeacherUid());
                r.setTeacherName(userDTO.getUserName());
                r.setTeacherLogo(userDTO.getLogo());
            }
        });
    }
}
